package com.example.demo.utils.TokenUtil;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.time.*;
import java.util.concurrent.TimeUnit;

import static com.example.demo.utils.Redis.RedisConstants.ONLINE_ADMINS;
import static com.example.demo.utils.Redis.RedisConstants.ONLINE_USERS;

@Component
public class OnlineUserStatsService {

    private static final Logger log = LoggerFactory.getLogger(OnlineUserStatsService.class);

    @Resource
    private StringRedisTemplate stringRedisTemplate;

    /**
     * 添加用户在线信息，并设置整个ZSet过期时间为7天
     *
     * @param userId 用户id
     */
    public void online(Integer userId) {
        if (userId == null) {
            log.error("用户id不合法");
            return;
        }

        double score = (double) Instant.now().toEpochMilli();
        this.stringRedisTemplate.opsForZSet().add(ONLINE_USERS, userId.toString(), score);
        // 设置键的过期时间为7天
        this.stringRedisTemplate.expire(ONLINE_USERS, 7, TimeUnit.DAYS);

        log.info("用户上线: userId=" + userId);
    }

    /**
     * 添加管理员在线信息，并设置整个ZSet过期时间为7天
     *
     * @param adminId 管理员id
     */
    public void adminOnline(Integer adminId) {
        if (adminId == null) {
            log.error("用户id不合法");
            return;
        }

        double score = (double) Instant.now().toEpochMilli();
        Boolean result = this.stringRedisTemplate.opsForZSet().add(ONLINE_ADMINS, adminId.toString(), score);
        // 确保为ONLINE_ADMINS键设置过期时间
        this.stringRedisTemplate.expire(ONLINE_ADMINS, 7, TimeUnit.DAYS);

        log.info("admin上线: userId=" + adminId);
    }

    /**
     * 获取用户在线状态的分数
     *
     * @param userId 用户ID
     * @return 用户的在线分数，如果用户不在线则返回null
     */
    public Double getScore(Integer userId) {
        if (userId == null) {
            return null;
        }

        String userIdStr = userId.toString();

        return this.stringRedisTemplate.opsForZSet().score(ONLINE_USERS, userIdStr);
    }

    /**
     * 获取admin在线状态的分数
     *
     * @param adminId adminID
     * @return admin的在线分数，如果admin不在线则返回null
     */
    public Double getAdminScore(Integer adminId) {
        if (adminId == null) {
            return null;
        }

        String userIdStr = adminId.toString();

        return this.stringRedisTemplate.opsForZSet().score(ONLINE_ADMINS, userIdStr);
    }

    /**
     * 退出登录时调用
     *
     * @param userId 用户id
     */
    public void outOnline(Integer userId) {
        if (userId == null) {
            log.error("用户id不合法: " + userId);
            return;
        }

        stringRedisTemplate.opsForZSet().remove(ONLINE_USERS, userId.toString());
        log.info("用户下线: userId=" + userId);
    }

    /**
     * 退出登录时调用
     *
     * @param adminId 管理员id
     */
    public Long adminOutOnline(Integer adminId) {
        if (adminId == null) {
            log.error("管理员id不合法: " + null);
            return 0L;
        }

        // 使用 Long 对象接收可能的 null 返回值
        Long removedCount = stringRedisTemplate.opsForZSet().remove(ONLINE_ADMINS, adminId.toString());

        // 检查 removedCount 是否为 null
        if (removedCount != null && removedCount > 0) {
            log.info("管理员下线成功: adminId=" + adminId);
            return removedCount; // 返回实际删除的元素数量
        } else {
            log.info("管理员下线失败或已不在线: adminId=" + adminId);
            return 0L; // 表示没有元素被删除
        }
    }



    /**
     * 获取一定时间内，在线的用户数量
     *
     * @param duration 与清除用户同理
     * @return
     */
    public Long count(Duration duration) {
        LocalDateTime now = LocalDateTime.now();
        return this.stringRedisTemplate.opsForZSet().count(ONLINE_USERS,
                now.minus(duration).atZone(ZoneId.systemDefault()).toInstant().toEpochMilli(),
                now.atZone(ZoneId.systemDefault()).toInstant().toEpochMilli());
    }

    /**
     * 获取今日活跃用户数量
     *
     * @return 今日活跃用户数量
     */
    public Long countTodayActiveUsers() {
        LocalDateTime startOfDay = LocalDateTime.of(LocalDate.now(), LocalTime.MIDNIGHT);
        LocalDateTime endOfDay = startOfDay.plusDays(1);

        double startScore = startOfDay.atZone(ZoneId.systemDefault()).toInstant().toEpochMilli();
        double endScore = endOfDay.atZone(ZoneId.systemDefault()).toInstant().toEpochMilli();

        return this.stringRedisTemplate.opsForZSet().count(ONLINE_USERS, startScore, endScore);
    }

    /**
     * 获取昨日活跃用户数量
     *
     * @return 昨日活跃用户数量
     */
    public Long countYesterdayActiveUsers() {
        // 昨天开始的时间
        LocalDateTime startOfYesterday = LocalDateTime.of(LocalDate.now().minusDays(1), LocalTime.MIDNIGHT);
        // 昨天结束的时间
        LocalDateTime endOfYesterday = startOfYesterday.plusDays(1);

        double startScore = startOfYesterday.atZone(ZoneId.systemDefault()).toInstant().toEpochMilli();
        double endScore = endOfYesterday.atZone(ZoneId.systemDefault()).toInstant().toEpochMilli();

        return this.stringRedisTemplate.opsForZSet().count(ONLINE_USERS, startScore, endScore);
    }


    /**
     * 获取所有在线过的用户数量，不论时间
     *
     * @return 在线个数
     */
    public Long countAll() {
        return this.stringRedisTemplate.opsForZSet().zCard(ONLINE_USERS);
    }

    /**
     * 清除超过一定时间没在线的用户数据
     *
     * @param duration 一定时间，如Duration.ofDays(7)指的是七天没有操作；Duration.ofHours(1)指的是一个小时没有操作
     * @return 清除用户
     */
    public Long clear(Duration duration) {
        return this.stringRedisTemplate.opsForZSet().removeRangeByScore(ONLINE_USERS, 0,
                LocalDateTime.now().minus(duration).atZone(ZoneId.systemDefault()).toInstant().toEpochMilli());
    }
}

